from PyQt4.QtCore import *
from PyQt4.QtCore import QAbstractTableModel
from PyQt4.QtCore import QModelIndex
from PyQt4.QtCore import QString
from PyQt4.QtCore import QVariant
from PyQt4.QtCore import Qt
from PyQt4.QtCore import SIGNAL
from PyQt4.QtGui import QAbstractItemView
from PyQt4.QtGui import QAction
from PyQt4.QtGui import QCursor
from PyQt4.QtGui import QHeaderView
from PyQt4.QtGui import QMenu
from PyQt4.QtGui import QTableView
from globals import Globals
import os


class PlayList(QTableView):

    def __init__(self, phonik):
        #parent constructor
        QTableView.__init__(self)

        self.phonik = phonik

        #setup ui
        self.setShowGrid(False)
        self.setSortingEnabled(True)
        self.verticalHeader().hide()
        self.horizontalHeader().setSortIndicatorShown(True)
        self.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.setSelectionMode(QAbstractItemView.ExtendedSelection)
        self.setContextMenuPolicy(Qt.CustomContextMenu)

        #drag and drop
        self.setDragDropMode(QAbstractItemView.DragDrop)
        self.setDragEnabled(True)
        self.setAcceptDrops(True)

        #model
        self.playListModel = PlayListModel(self, phonik)
        self.setModel(self.playListModel)
        self.horizontalHeader().setContextMenuPolicy(Qt.CustomContextMenu)

        #actions
        self.signals()


    def addRow(self, metaData):

        rowItems = []

        rowItems.append(metaData[QString('TRACKNUMBER')][0])
        rowItems.append(metaData[QString('TITLE')][0])
        rowItems.append(metaData[QString('ARTIST')][0])
        rowItems.append(metaData[QString('ALBUM')][0])
        rowItems.append(metaData[QString('DATE')][0])
        rowItems.append(metaData[QString('TIME')][0])
        rowItems.append(metaData[QString('GENRE')][0])
        rowItems.append(metaData[QString('URL')][0])

        self.playListModel.appendRow(rowItems, self.horizontalHeader().sortIndicatorSection (), self.horizontalHeader().sortIndicatorOrder ())


    def setColumnResizeMode(self, column):
        self.horizontalHeader().setResizeMode(QHeaderView.Interactive)
        self.horizontalHeader().setResizeMode(column, QHeaderView.Stretch)


    def showHeaderContextMenu(self):

        menu = QMenu()

        for i in range(0, self.playListModel.columnCount()):
            action = menu.addAction(self.playListModel.headerData(i, Qt.Horizontal).toString())
            action.setProperty('column', QVariant(i))
            action.setCheckable(True)
            if not self.isColumnHidden(i):
                action.setChecked(True)

        self.connect(menu, SIGNAL('triggered (QAction *)'), self.runHeaderContextMenu)
        menu.exec_(QCursor.pos())


    def runHeaderContextMenu(self, action):
        column = int(action.property('column').toString())
        self.setColumnHidden(column, not self.isColumnHidden(column))


    def showContextMenu(self, pos):
        actionList = [QAction(self.tr('Delete'), self), QAction(self.tr('Clear the playlist'), self)]
        result = QMenu().exec_(actionList, QCursor.pos())
        if result:
            if result.text() == self.tr('Delete'):
                rows = self.selectionModel().selectedRows()
                rows.sort()
                rows.reverse()
                for row in rows:
                    self.model().removeRow(row.row())
            elif result.text() == self.tr('Clear the playlist'):
                self.clearModel()


    def findCurrent(self):
        list = self.model ().match(self.model ().index(0, 7), Qt.DisplayRole, QVariant(QString.fromUtf8(self.phonik.mediaManager.currentUrl())), 1, Qt.MatchExactly)
        if list:
            self.setCurrentIndex (list[0])
            self.scrollTo(list[0])


    def clearModel(self):
        self.playListModel.removeRows()


    def setSortIndicator(self, column, order=Qt.AscendingOrder):
        self.horizontalHeader().setSortIndicator(column, order)


    def save(self):
        import pickle

        output = open(Globals.phonikPath + os.sep + 'playlist', 'wb')
        pickle.dump(self.playListModel.getData(), output, 2)
        output.close()


    def restore(self):
        import pickle
        input = open(Globals.phonikPath + os.sep + 'playlist', 'rb')
        self.playListModel.setAllData(pickle.load(input))
        input.close()


    def signals(self):
        self.connect(self.horizontalHeader(), SIGNAL('sectionDoubleClicked(int)'), self.setColumnResizeMode)
        self.connect(self.horizontalHeader(), SIGNAL('customContextMenuRequested(const QPoint &)'), self.showHeaderContextMenu)
        self.connect(self, SIGNAL('customContextMenuRequested(const QPoint &)'), self.showContextMenu)
        self.connect(self.playListModel, SIGNAL('layoutChanged()'), self.findCurrent)



class PlayListModel(QAbstractTableModel):
    def __init__(self, parent, phonik):
        QAbstractTableModel.__init__(self, parent)
        self.phonik = phonik

        #the main storage, matrix of QString
        self.table = []


    def index (self, row, column, parent=QModelIndex()):
        return  self.createIndex(row, column)


    def getData(self):
        return self.table


    def setAllData(self, table):
        self.table = table


    def insertRow(self, pos, row):
        self.insertRows(pos, 1, row)


    def insertRows(self, pos, count, rows):
        self.beginInsertRows(QModelIndex(), pos, pos + count-1)
        self.table.insert(pos, rows)
        self.endInsertRows()
        self.emit(SIGNAL('layoutChanged()'))
        return True


    def removeRow(self, pos):
        self.removeRows(pos, 1)
        return True


    def removeRows(self, row=-1, count=0, parent=QModelIndex()):
        if row == -1:
            self.beginRemoveRows(QModelIndex(), 0, len(self.table)-1)
            del self.table[:]
        else:
            self.beginRemoveRows(QModelIndex(), row, row + count-1)
            del self.table[row:row + count]
        self.endRemoveRows ()
        self.emit(SIGNAL('layoutChanged()'))
        return True


    def takeRow(self, row):
        rowData = self.table[row]
        self.removeRow(row)
        return rowData


    def appendRow(self, row, column=None, order=None):
        self.insertRows(len(self.table), 1, row)
        if column is not None:
            self.sort(column, order)


    def rowCount(self, parent=QModelIndex()):
        return len(self.table)


    def columnCount(self, parent=QModelIndex()):
        return Globals.columnsCount


    def supportedDropActions(self):
        return Qt.MoveAction | Qt.CopyAction


    def dropMimeData(self, data, action, row, column, parent):

        if action == Qt.IgnoreAction:
            return True

        if 'application/x-qabstractitemmodeldatalist' in data.formats():
            import pickle
            rowsPositions = pickle.loads(data.data("application/x-qabstractitemmodeldatalist"))
            theHighest = max(rowsPositions)


            rows = []
            for i in range(len(rowsPositions)):
                curPos = rowsPositions.pop()
                rows.append(self.takeRow(curPos - i))

            rowPos = parent.row()- len(rows)


            while rows:
                if theHighest < parent.row():
                    self.insertRow(rowPos, rows.pop())
                else:
                    self.insertRow(parent.row(), rows.pop())


            return True

        elif 'text/uri-list' in data.formats():
            import os

            for url in data.urls():
                url = str(url.path().toUtf8())
                if os.path.isdir(url):
                    self.phonik.playDir(url)
                else:
                    self.phonik.playUrls([url])
            return True

        return False


    def mimeTypes(self):
        return ['application/x-qabstractitemmodeldatalist', 'text/uri-list', 'text/plain']


    def mimeData(self, indexes):
        mimeData = QMimeData()

        rows = []

        row = -1
        uris = ''
        files = ''
        for i in range(0, len(indexes)):
            rows.append(indexes[i].row())
            if indexes[i].row() > row:
                path = str(indexes[i].sibling(indexes[i].row(), 7).data().toString().toUtf8())
                uris += path + '\n'
                files += 'file://' + path + '\n'
                row = indexes[i].row()


        import pickle
        mimeData.setData('application/x-qabstractitemmodeldatalist', pickle.dumps(set(rows), 2))
        mimeData.setData('text/uri-list', uris)
        mimeData.setData('text/plain', files)
        return mimeData


    def data(self, index, role=Qt.DisplayRole):

        if not index.isValid():
            return QVariant()


        if role != Qt.DisplayRole:
            return QVariant()

        if len(self.table) > index.row():
            return QVariant(self.table[index.row()][index.column()])
        return QVariant()



    def flags(self, index):
        return Qt.ItemIsDragEnabled | Qt.ItemIsDropEnabled | Qt.ItemIsEnabled | Qt.ItemIsSelectable

    def headerData(self, section, orientation, role=Qt.DisplayRole):
        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
            if section == 0:
                return QVariant('#')
            if section == 1:
                return QVariant(self.tr('Title'))
            if section == 2:
                return QVariant(self.tr('Artist'))
            if section == 3:
                return  QVariant(self.tr('Album'))
            if section == 4:
                return QVariant(self.tr('Date'))
            if section == 5:
                return QVariant(self.tr('Time'))
            if section == 6:
                return QVariant(self.tr('Genre'))
            if section == 7:
                return QVariant(self.tr('Url'))

        return QVariant()

    def sort (self, column, order=Qt.AscendingOrder):

        self.emit(SIGNAL('layoutAboutToBeChanged()'))
        if order == Qt.DescendingOrder:
            self.table.sort(key=lambda x: x[column], reverse=True)
        else:
            self.table.sort(key=lambda x: x[column])
        self.emit(SIGNAL('layoutChanged()'))





    def match (self, start, role, value, hits=1, flags=Qt.MatchStartsWith):
        for i in range(self.rowCount()):
            if value.toString() == self.table[i][7]:
                return [self.index(i, 0)]
        return None


    def parent(self, index):
        return QModelIndex()

    def update(self):
        self.emit(SIGNAL('layoutChanged()'))